package com.mobile.service.impl;

import com.mobile.service.convert.TaskAllocationRuleConverter;
import com.mobile.service.convert.WorkOrderConverter;
import com.mobile.service.dao.DaoSupport;
import com.mobile.service.dto.TaskAllocationRuleDTO;
import com.mobile.service.dto.TaskAllocationRuleQueryDTO;
import com.mobile.service.dto.WorkOrderDTO;
import com.mobile.service.entity.MessageNotification;
import com.mobile.service.entity.ProcessFlow;
import com.mobile.service.entity.TaskAllocationRule;
import com.mobile.service.inter.TaskAllocationRuleService;
import com.mobile.service.mapper.TaskAllocationRuleMapper;
import com.mobile.service.mapper.WorkOrderMapper;
import com.mobile.service.util.PageUtils;
import com.mobile.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 任务分配规则表service实现类
 */
@Service("taskAllocationRuleService")
@Transactional
public class TaskAllocationRuleServiceImpl implements TaskAllocationRuleService {
    private static final Logger logger = LoggerFactory.getLogger(TaskAllocationRuleServiceImpl.class);

    // 常量定义
    private static final String ALLOCATION_STATUS_SUBMITTED = "SUBMITTED";
    private static final String ALLOCATION_STATUS_AUDITING = "AUDITING";
    private static final String DISPATCH_TYPE_AUTO = "自动派工";
    private static final String DISPATCH_TYPE_MANUAL = "手动派工";
    private static final String SYSTEM_USER = "system";
    private static final String MESSAGE_TYPE_TASK_ASSIGNMENT = "分配消息";
    private static final String BUSINESS_AREA = "BUSINESS_AREA";
    private static final String DESIGNATED_STAFF = "DESIGNATED_STAFF";
    private static final String WORKLOAD_BALANCE = "WORKLOAD_BALANCE";
    private static final String CAR_INSURANCE = "CAR_INSURANCE";
    private static final String HEALTH_INSURANCE = "HEALTH_INSURANCE";
    private static final String LIFE_INSURANCE = "LIFE_INSURANCE";

    @Resource(name = "daoSupport")
    private DaoSupport dao;
    @Autowired
    private TaskAllocationRuleConverter taskAllocationRuleConverter;

    @Autowired
    private WorkOrderConverter workOrderConverter;

    @Autowired
    private WorkOrderMapper workOrderMapper;

    @Autowired
    private TaskAllocationRuleMapper taskAllocationRuleMapper;

    @Autowired
    private DataCommonService dataCommonService;


    @Override
    public Map<String, Object> addTaskAllocationRule(TaskAllocationRuleDTO dto) throws Exception {
        Map<String, Object> map = new HashMap<>();
        taskAllocationRuleMapper.insertTaskAllocationRule(taskAllocationRuleConverter.toEntity(dto));
        map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_SUCCESS);
        map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("I0011"));
        return map;
    }

    @Override
    public PageResult<TaskAllocationRuleDTO> getTaskAllocationRuleListPage(TaskAllocationRuleQueryDTO queryDTO) throws Exception {
        PageUtils.startPage(queryDTO);
        List<TaskAllocationRuleDTO> list = taskAllocationRuleMapper.taskAllocationRulelistPage(queryDTO);
        return new PageResult<TaskAllocationRuleDTO>(list);
    }

    @Override
    public TaskAllocationRuleDTO getTaskAllocationRuleById(Integer id) throws Exception {
        return taskAllocationRuleMapper.getTaskAllocationRuleById(id);
    }

    @Override
    public Map<String, Object> updateTaskAllocationRule(TaskAllocationRuleDTO dto) throws Exception {
        Map<String, Object> map = new HashMap<>();
        Integer pkValue = dto.getRuleId();
        if (pkValue == null) {
            map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_FAILED);
            map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("E0001"));
            return map;
        }

        TaskAllocationRuleDTO data = this.getTaskAllocationRuleById(pkValue);
        if (Objects.isNull(data)) {
            map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_FAILED);
            map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("E0001"));
            return map;
        }

        taskAllocationRuleMapper.updateTaskAllocationRule(taskAllocationRuleConverter.toEntity(dto));
        map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_SUCCESS);
        map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("I0009"));
        return map;
    }

    @Override
    public Map<String, Object> removeTaskAllocationRule(Integer id) throws Exception {
        Map<String, Object> map = new HashMap<>();
        taskAllocationRuleMapper.deleteTaskAllocationRule(id);
        map.put(Const.ACTION_RESULT, Const.ACTION_RESULT_SUCCESS);
        map.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("I0010"));
        return map;
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<TaskAllocationRuleDTO> getTaskAllocationRuleList(TaskAllocationRuleDTO queryDTO) throws Exception {
        return taskAllocationRuleMapper.getTaskAllocationRuleList(queryDTO);
    }

    @Override
    public void autoAssignTask() throws Exception {
        // 获取所有任务分配规则
        WorkOrderDTO orderDTO = new WorkOrderDTO();

        List<WorkOrderDTO> list = workOrderMapper.getUnfinishedWorkOrders(orderDTO);

        logger.info("开始自动分配任务，待处理工单数量: {}", list.size());

        for (WorkOrderDTO dto : list) {
            // 根据分配规则进行任务分派
            String allocationRule = dto.getAllocationRule();
            //判空使用工具类
            if (StringUtil.isEmpty(allocationRule)) {
                logger.warn("工单 {} 未设置分配规则，跳过处理", dto.getWorkOrderNo());
                continue;
            }

            String designatedStaff = "";
            //根据业务属地、审核专员、工作量负载等条件，选择合适的业务员进行任务分派
            switch (allocationRule) {
                case BUSINESS_AREA:
                    // 根据业务属地进行任务分派
                    designatedStaff = getStaffByBusinessArea(dto);
                    break;
                case DESIGNATED_STAFF:
                    // 根据审核专员进行任务分派
                    designatedStaff = dto.getDesignatedStaff();
                    break;
                case WORKLOAD_BALANCE:
                    // 根据工作量负载进行任务分派
                    designatedStaff = getStaffByWorkload(dto);
                    break;
                default:
                    // 默认分派规则
                    logger.warn("工单 {} 使用了未知的分配规则: {}", dto.getWorkOrderNo(), allocationRule);
                    designatedStaff = "";
                    break;
            }

            if (!StringUtil.isEmpty(designatedStaff)){
                dto.setDesignatedStaff(designatedStaff);
                assignTask(dto, DISPATCH_TYPE_AUTO, SYSTEM_USER);
                logger.info("工单 {} 已自动分配给业务员 {}", dto.getWorkOrderNo(), designatedStaff);
            } else {
                logger.warn("工单 {} 未能找到合适的业务员进行分配", dto.getWorkOrderNo());
            }
        }
    }

    @Override
    public Map<String, Object> manualAssignment(Integer workOrderId,String designatedStaff,String userCode,String reason)  {
        WorkOrderDTO dto = workOrderMapper.getWorkOrderById(workOrderId);
        Map<String, Object> result = new HashMap<>();
        if(ALLOCATION_STATUS_SUBMITTED.equals(dto.getAllocationStatus())){
            dto.setDesignatedStaff(designatedStaff);
            dto.setAllocationReason(reason);
            assignTask(dto, DISPATCH_TYPE_MANUAL, userCode);
            result.put(Const.ACTION_RESULT, Const.ACTION_RESULT_SUCCESS);
            result.put(Const.ACTION_MESSAGE, "任务分配成功");
            return result;
        }
        result.put(Const.ACTION_RESULT, Const.ACTION_RESULT_EXCEPTION);
        result.put(Const.ACTION_MESSAGE, MessageUtil.getMessage("E0016"));
        return result;
    }

    /**
     * 分配任务的通用方法
     * @param dto 工单信息
     * @param dispatchType 派工类型
     * @param dispatcherId 派工人ID
     * @throws Exception 异常
     */
    private void assignTask(WorkOrderDTO dto, String dispatchType, String dispatcherId) {
        // 创建流程记录
        ProcessFlow processFlow = new ProcessFlow();

        processFlow.processorId(dto.getDesignatedStaff())
                .currentReviewStatus(ALLOCATION_STATUS_AUDITING)
                .applicantId(dto.getApplicantId())
                .dispatchType(dto.getDispatchType())
                .workOrderId(dto.getWorkOrderId())
                .estimatedReviewDuration(getEstimatedDuration(dto.getInsuranceType()))
                .dispatchType(dispatchType)
                .dispatcherId(dispatcherId)
                .createUser(dispatcherId)
                .updateUser(dispatcherId);
        dto.setAllocationStatus(ALLOCATION_STATUS_AUDITING);

        //新增数据至消息通知表
        MessageNotification message = new MessageNotification();
        message.personId(dto.getDesignatedStaff())
                .messageType(MESSAGE_TYPE_TASK_ASSIGNMENT)
                .messageContent("您已被分配了新的任务，请及时处理。")
                .messageStatus(0)
                .createUser(dispatcherId)
                .updateUser(dispatcherId);

        dataCommonService.autoAssignTask(processFlow, workOrderConverter.toEntity(dto), message);
    }

    /**
     * 根据业务属地获取业务员
     * @param dto 工单信息
     * @return 业务员ID
     */
    private String getStaffByBusinessArea(WorkOrderDTO dto) throws Exception {
        PageData paramMap = new PageData();
        paramMap.put("district", dto.getBusinessLocation());

        List<PageData>  staffList = (List<PageData>)dao.findForList("UserMapper.getUserListForSearch", paramMap);

        if (staffList != null && !staffList.isEmpty()) {
            // 返回第一个匹配的业务员
            return (String) staffList.get(0).get("userCode");
        }
        return null;
    }


    /**
     * 根据工作负载获取最空闲的业务员
     * @return 业务员ID
     */
    private String getStaffByWorkload(WorkOrderDTO dto) {
        return workOrderMapper.getStaffByWorkload();
    }

    /**
     * 获取预计审核时长
     * @param insuranceType 险种类型
     * @return 预计审核时长（小时）
     */
    private int getEstimatedDuration(String insuranceType) {
        // 根据险种类型返回预设的审核时长（小时）
        switch (insuranceType) {
            case CAR_INSURANCE:
                return 2;
            case HEALTH_INSURANCE:
                return 4;
            case LIFE_INSURANCE:
                return 8;
            default:
                return 3;
        }
    }

}
